﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.IO.Pipes;
using System.Windows.Forms;
using System.Runtime.Serialization.Formatters.Binary;

namespace ProjetReseau
{
    class Transport
    {
        private const int NON_CONNECTE = 0;
        private const int EN_ATTENTE = 1;
        private const int CONNECTE = 2;

        private int[] etat; // NON_CONNECTE, EN_ATTENTE ou CONNECTE

        private Reseau reseau;

        private List<string>[] data;

        private byte adSource;

        public Transport()
        {
            etat = new int[250];
            data = new List<string>[250];
            adSource = this.randomAdresse(); // generer l'adresse source pour la duree des connexions

            Thread thLireReseau = new Thread(this.lireDeReseau);

            thLireReseau.Start();

            lireS_lec();

        }

        public void lireDeReseau()
        {
            while (true)
            {
                using (NamedPipeServerStream pipeServer =
                new NamedPipeServerStream( "restotrans", PipeDirection.In))
                {
                    pipeServer.WaitForConnection();

                    
                    BinaryFormatter bf = new BinaryFormatter();

                    Primitive prim = (Primitive)bf.Deserialize(pipeServer);


                    byte adresse = prim.adresseReponse;

                    switch (prim.type)
                    { 
                        case "N_CONNECT.conf":
                                
                            while (data[adresse].Count > 0)
                            {
                                Primitive datareq = new Primitive(adresse, data[adresse][0], "N_DATA.req");

                                data[adresse].RemoveAt(0);

                                ecrireVersReseau(datareq);
                            }

                            Primitive disconnect = new Primitive(adresse, "N_DISCONNECT.req");

                            ecrireVersReseau(disconnect);

                            etat[adresse] = 0;

                        break;

                        case "N_DISCONNECT.ind":
                            etat[adresse] = 0;
                        break;
                    }

                    ecrireS_ecr(prim.ToString());
                }
            }
        }

        public void ecrireVersReseau(Primitive prim)
        {
            using (NamedPipeClientStream pipeClient =
            new NamedPipeClientStream(".", "transtores", PipeDirection.Out))
            {

                bool retry = false;
                do
                {
                    try
                    {
                        while (!pipeClient.IsConnected)
                            pipeClient.Connect(500);
                    }
                    catch (IOException e)
                    {
                        retry = true;
                    }
                }
                while (retry);

                BinaryFormatter bf = new BinaryFormatter();

                bf.Serialize(pipeClient, prim);

                pipeClient.WaitForPipeDrain();
                pipeClient.Close();
                pipeClient.Dispose();
            }
        }

        public void lireS_lec()
        {
            StreamReader sr = File.OpenText("S_lec.txt");

            string temp;
            while ((temp = sr.ReadLine()) != null)
            {
                byte adresse = randomAdresse();

                switch (etat[adresse])
                { 
                    case NON_CONNECTE:
                        Primitive prim = new Primitive(adSource, adresse, "N_CONNECT.req");

                        etat[adresse] = EN_ATTENTE;

                        data[adresse] = new List<string>();

                        data[adresse].Add(temp);

                        ecrireVersReseau(prim);
                        break;
                    default:
                        data[adresse].Add(temp);
                        break;
                }
            }
        }

        public void ecrireS_ecr(string line)
        {
            StreamWriter sw = File.AppendText("S_ecr.txt");

            sw.WriteLine(line);

            sw.Close();
            sw.Dispose();
        }

        private byte randomAdresse()
        {
            Random random = new Random();
            byte adressDestination = (byte)random.Next(1, 249);

            if (this.adSource == adressDestination)
            {
                adressDestination = this.randomAdresse();
            }


            
            return adressDestination;
        }
    }
}

